﻿/**
 * 面板模块 - 核心模块 -- 可选
 *
 * 实现面板功能，面板模块主要由插件来调用。
 * 面板用来生成插件的操作见面，插件需要将具体的html代码告诉面板组件。
 *
 * 不要在这里包含和面板功能不相干的功能。
 */
(function(E, $){

var Consts = E.consts,
	isShow = false,
	panelActionButton = '.jqe-panel-button input, .jqe-panel-close',
	panelLockedMsg = '提示：窗口正在进行数据处理，请稍等...';

function getPanel( ){
	var option = E.get('option'), name = option.panel;
	if( 'Dialog' == name ){
		return PanelDialog;
	}else{
		return PanelDefault;
	}
}

//对外公开的对象
E.mod("Panel", {
	get: function(pluginName){
		return $("#panel_"+pluginName);
		//return $(".jqe-panel:visible");
	},
	set: function( Plugin ){
		var option = E.get('option'), Panel = getPanel( );

		Panel.set( Plugin );
		isShow = true;
	},

	hide: function( ){
		var Panel = getPanel( );
		Panel.hide( );
		isShow = false;
	},

	error: function( msg ){
		var Panel = getPanel( );
		Panel.error( msg );
	},

	notice: function( msg ){
		var Panel = getPanel( );
		Panel.notice( msg );
	},

	lock: function( panel ){
		var self = this;
		panel.find( panelActionButton ).css('opacity', 0.3).click(function(){
			E.alert( panelLockedMsg );
			return false;
		});
	},

	unlock: function( panel ){
		panel.find( panelActionButton ).css('opacity', 1).unbind('click');
	},

	isShow: function( Plugin ){
		if( Plugin ){
			var panel = $("#panel_" + Plugin.name);
			return panel.size() && panel.is(':visible') &&  E.eid == panel.attr('eid');
		}else{
			return isShow;
		}
	}
});


//内部私有对象
var PanelDefault = {
	//记录上一次的E.eid
	eid:'',
	cmd:'',
	target: null,
	panel: null,
	panel_id: '',

	set: function( Plugin ){
		var self=this, panel, panel_id;
		panel_id = self.panel_id = 'panel_' + Plugin.name;
		panel = $("#"+panel_id);
		E.log("run", "开始构建面板"+panel_id);
		if( panel.size() ){
		//面板存在
			if(panel.is(':visible') &&  E.eid == panel.attr('eid')){
			//并且处于显示状态
				//将其置为隐藏状态，终止
				E.hidePanel( );
				return panel;
			}
		}else {
		//面板不存在，则创建它
			panel = self.build( Plugin );
			//第一次创建后设置宽高
			self.setSize( Plugin );

			if( typeof Plugin.one === 'function' ){
				Plugin.one(panel, Plugin);
			}
		}

		self.panel = panel;
		Plugin.panel = panel;
		self.reset( );
		// callback方法一定要在reset方法后面
		// 否则在callback当中进行的赋值操作，将被reset()方法取消
		if( typeof Plugin.callback === 'function' ){
			Plugin.callback(panel, Plugin);
		}

		self.show( Plugin );
		return panel;
	},

	//隐藏面板
	hide: function(  ){
		var self = this, pluginName, panel = $(".jqe-panel:visible");

		pluginName = panel.attr('id');

		if( !pluginName ){
			return false;
		}

		// 执行插件可能存在的onclose事件
		if( pluginName ){
			pluginName = pluginName.replace('panel_', '');
			var Plugin = E.plugin(pluginName);

			if( Plugin.islock() ){
				return false;
			}

			if( typeof Plugin.onclose === 'function' ){
				Plugin.onclose(panel, Plugin );
			}

			panel.hide();
		}

		$('.jqe-button-hover').removeClass('jqe-button-hover');

		// 关闭遮罩层
		self.hideOverlay();
		return true;
	},

	// 显示面板
	show: function( Plugin ){
		E.log("run", "开始显示面板("+Plugin.name+")");
		var self = this, panel=self.panel,
			title = Plugin.title || Plugin.getTitle(),
			jqTitle = panel.find('.jqe-panel-title');

		if(title){
			jqTitle.unbind('selectstart')
				.bind('selectstart', function(){return false;})
				.show().find('strong').text(title);
		}else{
			jqTitle.hide();
		}

		// 需要先隐藏掉所有的面板
		self.hide();

		self.cmd = Plugin.name;
		self.eid = E.eid;
		panel.show().attr('eid', E.eid);

		E.log("run", "面板("+Plugin.name+")显示结束");

		self.setPosition( Plugin );
		if( Plugin.config && Plugin.config.overlay ){
			self.showOverlay();
		}

		var textInput = panel.find(':text:visible,textarea:visible');
		if( textInput.size() ){
			textInput[0].focus();
		}

	},

	/**
	 * 构建面板代码并绑定点击事件
	 * 1.面板会为每个插件创建一个面板对象；
	 * 2.多个编辑器的同一个插件共享一个面板对象；
	 */
	build: function( Plugin ){
		var self = this, html=[], panel, panel_id=self.panel_id;

		//组装面板的HTML代码，调用插件的panelHtml()方法
		html.push('<div id="'+ panel_id +'" class="jqe-panel');
		if(Plugin.isNeedTitle){
			html.push('"><div class="jqe-panel-title"><strong></strong><a name="panel-close" class="jqe-panel-close" title="关闭">X</a></div>');
		}else{
			html.push(' jqe-panel-notitle">');
		}

		// 使用iframe反而会导致面板内容被iframe遮盖，暂时取消
		// ie6 下div层需要使用iframe遮罩下面的select标签
		//if( Consts.IE6 ){
		//	html.push('<iframe scrolling="no" frameborder="0" style="position:absolute; top:0px; left:0px; display:block;width:100%;height:100%;"></iframe>');
		//}

		html.push('<form onsubmit="return false" ');
		if( Plugin.form && Plugin.form.action ){
			var form = Plugin.form;
			form.target = form.target || 'jqe_iframe_submit';
			form.method = form.method || 'post';
			form.enctype = form.enctype || 'multipart/form-data';

			html.push(' action="'+ form.action +'" method="'+ form.method +'" enctype="'+ form.enctype +'"');

		}
		html.push('>');
		html.push('<div class="jqe-panel-body"><div class="jqe-panel-notice"></div>');
		var panelHtml = Plugin.panelHtml();

		if( !panelHtml ){
			Plugin.init(Plugin);
			panelHtml = Plugin.panelHtml();
		}

		html.push( panelHtml );
		html.push('<div class="jqe-panel-error"></div></div>');


		// 2011-08-31 潘雪鹏
		// 下面有副作用取消使用，在ie6/7下会导致颜色、字体等功能失效

		// 方便ie6/7强制将光标定位到面板，避免光标在面板下面闪烁
		//if( $.browser.msie && $.browser.version < 8 ){
		//	html.push('<input name="force-cursor" type="text" style="border:0;width:1px;height:1px;position:absolute;"/>');
		//}
		// 上面 2011-08-31 取消

		//显示面板下面的确定和关闭按钮
		if(typeof Plugin.get === 'function' || typeof Plugin.ok === 'function'){
			html.push('<div class="jqe-panel-button">');
			html.push('<input name="panel-submit" type="submit" value=" 确 定 "/>');
			html.push('<input name="panel-close" type="button" value=" 取 消 "/>');
			html.push('</div>');
		}

		html.push('</form>');
		html.push('</div>');

		$("body").append( html.join('') );

		panel = self.panel = $("#"+panel_id);

		//绑定点击事件
		//在面板上点击会触发面板的 Panel.action() 方法
		panel.click(function( e ){
			var target = self.target = $(e.target),
				name = target.closest('[name]').attr('name');

			var bool = self.action( Plugin, panel, name );

			// 2011-06-03 潘雪鹏
			//此处不能禁止事件冒泡，
			//否则可能会导致点击面板上的checkbox radio file等控件时不能正常工作，
			//所以不能 return false
			//return false;

			return ( bool === false ) ? false : null;
		}).mouseover(function( e ){
			var pluginName = $(this).attr("id").replace("panel_", "");
			$("#"+E.eid+"-"+pluginName).addClass("jqe-button-hover");
		});

		//2011-02-11 18:13
		//不能直接给 panel 绑定 return false 事件，
		//这样将导致光标不能点击进上面的输入框。
		//如果需要绑定，则需要进行处理，判断事件的来源是否是input等，
		//目前还没有这个需求。
		//panel.mousedown(function(){return false;}).mouseup(function(){return false;});


		var events = Plugin.killEvents;
		if(events && $.isArray( events )){
			panel.bind(events.join(' '), Consts.returnFalse);
		}

		//方便开发阶段调试，利用firebug等工具，使用右键查看元素之类的操作
		if( !E.debug ){
			panel.bind('contextmenu', function( e ){
				if( $(e.target).is(":text,textarea") ){
					return true;
				}
				return false;
			});
		}
		return panel;
	},

	/**
	 * 设置面板的尺寸
	 * @param Plugin object 插件对象
	 */
	setSize: function( Plugin ){
		var self=this, panel=self.panel, width=600,
			config={width: width},
			maxWidth = $('#'+E.eid).width();

		if( Plugin.config ){
			config = $.extend(config, Plugin.config);
		}
		width = (config.width <= maxWidth )? config.width :maxWidth;
		//先设置面板的宽和高
		panel.css({width:width});
		config.height && panel.find(".jqe-panel-body").css({height:config.height});

		//panel的height最好是auto，显示错误信息时，面板高度会自动改变
		//所以config.height 赋值给了jqe-panel-body

		config.HEIGHT && panel.css({height:config.HEIGHT});
	},

	/**
	 * 设置面板的显示位置
	 * 1.如果面板较宽，比如大于300px，默认会居中显示；
	 * 2.默认和插件按钮的左侧对齐显示；
	 * 3.如果左侧对齐后，发现右侧超出编辑器区域，则实行右侧对齐；
	 * @param Plugin object 插件对象
	 */
	setPositionWithButton: function( Plugin ){
		var self=this,
			width=600,
			config={width: width},
			btn = Plugin.target.closest('.jqe-button'),
			box = $('#'+E.eid).find('.jqe-toolbar'),
			maxWidth = box.width();

		if( Plugin.config ){
			config = $.extend(config, Plugin.config);
		}
		width = (config.width <= maxWidth )? config.width :maxWidth;

		//定位面板显示位置
		var top, left, boxOffset = box.offset(), btnOffset = btn.offset();
		top = btnOffset.top + btn.height() + 1;

		//alert(document.compatMode); CSS1Compat/BackCompat

		if(config.align == 'left'){
		//强制和按钮的左侧对齐
			left = btnOffset.left;

		}else if( maxWidth > width && width > 400){
		//面板宽度大于400则居中显示
			left = boxOffset.left + (maxWidth - width)/2 - 3;
		}else{
		//小于等于400则和按钮左侧或右侧对齐

			//默认和按钮左侧对齐
			left = btnOffset.left;

			//判断面板右侧是否超出工具栏的右侧，
			//如果超出则和按钮右侧对齐
			if(left + width > boxOffset.left + maxWidth){
				left = left - width + btn.width();
			}
		}

		return {top:top, left:left};
	},

	setPosition: function( Plugin ){
		var self = this,
			fixed = false,
			e = Plugin.event,
			left, top, pos,
			config = Plugin.config,
			width = self.panel.width(),
			height = self.panel.height(),
			scrollTop = 0;

		if( Consts.IE6 ){
			scrollTop = $(document).scrollTop() || document.documentElement.scrollTop;
		}

		E.log("run", "开始设置面板显示位置("+Plugin.name+")");

		// 如果事件由工具栏来
		if( /^(center|middle)$/i.test(config.position) ){
			//居中显示
			left = ($(window).width() - width) / 2;
			top = scrollTop + ($(window).height() - height)/2;
			pos = {left: left, top:top};
			if( !Consts.IE6 ){
				self.panel.css('position', 'fixed');
				fixed = true;
			}
		}else if( e ){
			if( $(e.target).closest('.jqe-button').size() ){
				pos = self.setPositionWithButton( Plugin );

			}else {
				// 根据事件的位置显示
				left = e.pageX - 80;
				top = e.pageY - 40;
				if(left < 20){left = 20;}
				if(top < 20){top = 20;}

				pos = {left: left, top:top};
			}
			self.panel.css('position', 'absolute');
		}else{

		}

		//如果 body 是 relatiove 定位，很肯能导致面板定位不准确。
		//理想情况是body居中，则计算一下body 和 //窗口宽度差然后除以2，如果小于0，则用left减去即可
		if( !fixed && $("body").css("position") == "relative"){
			var _W = ($(window).width() - $("body").width())/2;
			if ( _W>0 ) pos.left -= _W;
		}

		return self.panel.css( pos );
	},

	/**
	 * 点击面板响应

	 * @param target jQuery 点击事件来源对象
	 */
	action: function( Plugin, panel, name ){
		var self = this, target = self.target, html='';

		name = name || target.closest('[name]').attr('name');

		if( 'panel-close' === name ){
			//点击面板[关闭]按钮
			if( self.hide() ){
				// 取消后将光标定位到编辑器区域
				// E.focus();

				// 2011-09-06 潘雪鹏
				// 取消了 E.focus() ，会导致将光标定位到编辑器顶部

				E.pluginExit();
				return false;
			}
		}else if( 'panel-submit' === name ){
			// 若插件存在验证方法check()，并且check没有返回true，则终止事件
			if( typeof Plugin['check'] === 'function' && !Plugin.check( panel, Plugin ) ){
				return false;
			}

			if( typeof Plugin['ok'] === 'function' ){
				if( Plugin.ok( panel, Plugin ) ){
					if( self.hide() ){
						//E.focus();
					}
					E.monitor(Plugin.name);
				}
			}else if( typeof Plugin['get'] === 'function' ){
				//点击面板[确定]按钮，调用插件的 get 方法获取要插入到编辑器的html代码
				html = Plugin.get( panel, Plugin, target );

				if ( html ){
					//将数据添加到编辑器光标处
					Plugin.pasteHTML( html );
					self.hide( );
					E.monitor(Plugin.name);
				}
			}
			E.pluginExit();
		}else if( Plugin.action ){
			E.Plugin = Plugin;
			//将点击行为传递给插件
			html = Plugin.action( target, panel, Plugin );

			if ( html ){
				//将数据添加到编辑器光标处
				Plugin.pasteHTML( html );
				self.hide( );
				E.monitor(Plugin.name);
				E.pluginExit();
				// 避免在IE下点击链接导致页面跳转
				return false;
			}else if( false === html ){
				E.pluginExit();
				// 插件返回false， 希望禁止事件冒泡
				return false;
			}else{
				return true;
			}
		}else{
			//待定

		}
	},

	/**
	 * 初始化面板状态
	 */
	reset: function( ){
		var panel = this.panel;
		//清楚错误信息
		panel.find('.jqe-panel-error').html('').hide();
		//重置表单项
		panel.find('form').trigger('reset');

		//将编辑器当中选中的字符串初始化到面板指定的文本框中
		var text = '', Selection, input = panel.find(":text[fill=Selection]");
		if( input.size() ){
			Selection = E.mod("Selection");
			if( Selection ){
				text = Selection.get('text');
			}

			if(text){
				input.val(text);
			}
		}
	},

	/**
	 * 显示提示信息
	 * @param msg string 提示信息
	 */
	error: function( msg ){
		this.panel.find('.jqe-panel-error').html(msg).show();
	},

	/**
	 * 显示提示信息
	 * @param msg string 提示信息
	 */
	notice: function( msg ){
		this.panel.find('.jqe-panel-notice').html(msg).show();
	},


	// 显示遮罩层
	showOverlay: function( ){
		var overlay = $(".jqe-panel-overlay"),
			docWidth = $(document).width(),
			docHeight = $(document).height(),
			winWidth = $(window).width(),
			winHeight = $(window).height();

		if( !overlay.size() ){
			$('body').append('<div class="jqe-panel-overlay"></div>');
			overlay = $(".jqe-panel-overlay");
		}

		overlay.show().height( docHeight );

		if( Consts.IE6 ){
			if( docHeight >= winHeight ){
				docWidth -= 21;
			}

			overlay.width( docWidth );
		}
	},

	// 隐藏遮罩层
	hideOverlay: function( ){
		var overlay = $(".jqe-panel-overlay");
		overlay.hide();
	}
}


// 显示面板后，阻止鼠标滚轮滚动页面
function stopMousewheel(target, up){
	var scrollTop = target.scrollTop(),
		height = target.outerHeight(),
		scrollHeight = target[0].scrollHeight;

	//E.log("run", ''+(scrollTop + height) +':'+ scrollHeight);
	if( up && !scrollTop ){
		return false;
	}else if( !up && (scrollTop + height) >= scrollHeight ){
		return false;
	}
	return true;
}

if( $.browser.mozilla ){
	window.addEventListener("DOMMouseScroll", function(e){
		// E.log("run", e.detail);
		// 2012-02-03 潘雪鹏
		// firefox 貌似不行，暂不处理吧
	}, false);
}else{
	$(".jqe-panel textarea").live("mousewheel", function( e ){
		if( e.originalEvent.wheelDelta ){
			var up = e.originalEvent.wheelDelta > 0;
			return stopMousewheel($(e.target), up);
		}
	});
}
/**
 * 和 Panel 并列的另外一种实现方式，以满足多种展现方式的需求
 */
var PanelDialog = {
	show: function( option ){

	}
}

})(jQEditor, jQuery);